module axi_spi#(
    parameter AXI_ID_WIDTH      = 4,
    parameter AXI_ADDR_WIDTH    = 32,
    parameter AXI_DATA_WIDTH    = 64,
    parameter AXI_USER_WIDTH    = 4
)(
    input     clk,    // Clock
    input     rst_n,  // Asynchronous reset active low
    output                         axi_arready  , 
    input                          axi_arvalid  , 
    input   [ AXI_ADDR_WIDTH-1:0]  axi_araddr   , 
    input   [2:0]                  axi_arprot   , 
    input   [ AXI_ID_WIDTH-1:0]    axi_arid     , 
    input   [ AXI_USER_WIDTH-1:0]  axi_aruser   , 
    input   [7:0]                  axi_arlen    , 
    input   [2:0]                  axi_arsize   , 
    input   [1:0]                  axi_arburst  , 
    input                          axi_arlock   , 
    input   [3:0]                  axi_arcache  , 
    input   [3:0]                  axi_arqos    , 
    input                          axi_rready   , 
    output                         axi_rvalid   , 
    output [1:0]                   axi_rresp    , 
    output [AXI_DATA_WIDTH-1:0]    axi_rdata    , 
    output                         axi_rlast    , 
    output [AXI_ID_WIDTH-1:0]      axi_rid      , 
    output [AXI_USER_WIDTH-1:0]    axi_ruser    , 
    output                         axi_awready  , 
    input                          axi_awvalid  , 
    input  [AXI_ADDR_WIDTH-1:0]    axi_awaddr   , 
    input  [2:0]                   axi_awprot   , 
    input  [AXI_ID_WIDTH-1:0]      axi_awid     , 
    input  [AXI_USER_WIDTH-1:0]    axi_awuser   , 
    input  [7:0]                   axi_awlen    , 
    input  [2:0]                   axi_awsize   , 
    input  [1:0]                   axi_awburst  , 
    input                          axi_awlock   , 
    input  [3:0]                   axi_awcache  , 
    input  [3:0]                   axi_awqos    , 
    output                         axi_wready   , 
    input                          axi_wvalid   , 
    input  [AXI_DATA_WIDTH-1:0]    axi_wdata    , 
    input  [AXI_DATA_WIDTH/8-1:0]  axi_wstrb    , 
    input                          axi_wlast    , 
    input  [AXI_USER_WIDTH-1:0]    axi_wuser    ,
    input                          axi_bready   , 
    output                         axi_bvalid   , 
    output [1:0]                   axi_bresp    , 
    output [AXI_ID_WIDTH-1:0]      axi_bid      , 
    output [AXI_USER_WIDTH-1:0]    axi_buser    ,

    output                                      spi_clk  ,
    output                                      spi_csn0 ,
    output                                      spi_csn1 ,
    output                                      spi_csn2 ,
    output                                      spi_csn3 ,
    output                                      spi_sdo0 ,
    output                                      spi_sdo1 ,
    output                                      spi_sdo2 ,
    output                                      spi_sdo3 ,
    output                                      spi_oe0  ,
    output                                      spi_oe1  ,
    output                                      spi_oe2  ,
    output                                      spi_oe3  ,
    input                                       spi_sdi0 ,
    input                                       spi_sdi1 ,
    input                                       spi_sdi2 ,
    input                                       spi_sdi3 
);

wire                          PENABLE;
wire                          PWRITE ;
wire [AXI_ADDR_WIDTH-1:0]    PADDR  ;
wire                          PSEL   ; 
wire [AXI_DATA_WIDTH-1:0]    PWDATA ;
wire [AXI_DATA_WIDTH-1:0]    PRDATA ;
wire                          PREADY ;
wire                          PSLVERR;

axi2apb #(
    .AXI4_ADDRESS_WIDTH ( AXI_ADDR_WIDTH ),
    .AXI4_RDATA_WIDTH   ( AXI_DATA_WIDTH ),
    .AXI4_WDATA_WIDTH   ( AXI_DATA_WIDTH ),
    .AXI4_ID_WIDTH      ( AXI_ID_WIDTH   ),
    .AXI4_USER_WIDTH    ( AXI_USER_WIDTH ),
    .APB_ADDR_WIDTH     ( AXI_ADDR_WIDTH )
)axi2apb(
    .ACLK      (clk   ),
    .ARESETn   (rst_n),
    .test_en_i (1'b0),

    .AWID_i      ( axi_awid     ),
    .AWADDR_i    ( axi_awaddr   ),
    .AWLEN_i     ( axi_awlen    ),
    .AWSIZE_i    ( axi_awsize   ),
    .AWBURST_i   ( axi_awburst  ),
    .AWLOCK_i    ( axi_awlock   ),
    .AWCACHE_i   ( axi_awcache  ),
    .AWPROT_i    ( axi_awprot   ),
    .AWREGION_i  ( axi_awregion ),
    .AWUSER_i    ( axi_awuser   ),
    .AWQOS_i     ( axi_awqos    ),
    .AWVALID_i   ( axi_awvalid  ),
    .AWREADY_o   ( axi_awready  ),

    .WDATA_i     ( axi_wdata ),
    .WSTRB_i     ( axi_wstrb ),
    .WLAST_i     ( axi_wlast ),
    .WUSER_i     ( axi_wuser ),
    .WVALID_i    ( axi_wvalid),
    .WREADY_o    ( axi_wready),

    .BID_o       ( axi_bid    ),
    .BRESP_o     ( axi_bresp  ),
    .BVALID_o    ( axi_bvalid ),
    .BUSER_o     ( axi_buser  ),
    .BREADY_i    ( axi_bready ),

    .ARID_i       ( axi_arid     ),
    .ARADDR_i     ( axi_araddr   ),
    .ARLEN_i      ( axi_arlen    ),
    .ARSIZE_i     ( axi_arsize   ),
    .ARBURST_i    ( axi_arburst  ),
    .ARLOCK_i     ( axi_arlock   ),
    .ARCACHE_i    ( axi_arcache  ),
    .ARPROT_i     ( axi_arprot   ),
    .ARREGION_i   ( axi_arregion ),
    .ARUSER_i     ( axi_aruser   ),
    .ARQOS_i      ( axi_arqos    ),
    .ARVALID_i    ( axi_arvalid  ),
    .ARREADY_o    ( axi_arready  ),

    .RID_o        ( axi_rid   ),
    .RDATA_o      ( axi_rdata ),
    .RRESP_o      ( axi_rresp ),
    .RLAST_o      ( axi_rlast ),
    .RUSER_o      ( axi_ruser ),
    .RVALID_o     ( axi_rvalid),
    .RREADY_i     ( axi_rready),

    .PENABLE      (PENABLE),
    .PWRITE       (PWRITE ),
    .PADDR        (PADDR  ),
    .PSEL         (PSEL   ),
    .PWDATA       (PWDATA ),
    .PRDATA       (PRDATA ),
    .PREADY       (PREADY ),
    .PSLVERR      (PSLVERR)
);


apb_spi_master apb_spi(
    .HCLK    ( clk     ),
    .HRESETn ( rst_n   ),
    .PADDR   ( PADDR   ),
    .PWDATA  ( PWDATA  ),
    .PWRITE  ( PWRITE  ),
    .PSEL    ( PSEL    ),
    .PENABLE ( PENABLE ),
    .PRDATA  ( PRDATA  ),
    .PREADY  ( PREADY  ),
    .PSLVERR ( PSLVERR ),

    .events_o (),
    
    .spi_clk  ( spi_clk  ),
    .spi_csn0 ( spi_csn0 ),
    .spi_csn1 ( spi_csn1 ),
    .spi_csn2 ( spi_csn2 ),
    .spi_csn3 ( spi_csn3 ),
    .spi_sdo0 ( spi_sdo0 ),
    .spi_sdo1 ( spi_sdo1 ),
    .spi_sdo2 ( spi_sdo2 ),
    .spi_sdo3 ( spi_sdo3 ),
    .spi_oe0  ( spi_oe0  ),
    .spi_oe1  ( spi_oe1  ),
    .spi_oe2  ( spi_oe2  ),
    .spi_oe3  ( spi_oe3  ),
    .spi_sdi0 ( spi_sdi0 ),
    .spi_sdi1 ( spi_sdi1 ),
    .spi_sdi2 ( spi_sdi2 ),
    .spi_sdi3 ( spi_sdi3 )
);


endmodule
